﻿using Newtonsoft.Json;

namespace vztools
{
    public class ScriptManager
    {
        private static string[] _innerArgs = new string[] { "new", "import", "open" };
        private string _scriptsDir;
        private List<ScriptInfo> _scripts;

        public ScriptManager(Config config)
        {
            this._scriptsDir = config.ScriptDirectory;
            _scripts = new List<ScriptInfo>();
            InitScripts();
        }

        private bool TryGetScript(string dir, out Script? script)
        {
            script = null;
            string infoFilePath = Path.Join(dir, "info.json");
            if (!File.Exists(infoFilePath))
                return false;
            string jsonStr = File.ReadAllText(infoFilePath);
            script = JsonConvert.DeserializeObject<Script>(jsonStr);
            return script != null && !string.IsNullOrEmpty(script?.Name);
        }

        private string FindScriptFile(Script script, string dir)
        {
            string fileName = $"{script.Name?.ToLower() ?? ""}.{script.Extension?.ToLower() ?? ""}";
            var mainFile = Directory.GetFiles(dir)
                            .FirstOrDefault(x => Path.GetFileName(x).ToLower() == fileName);
            return mainFile ?? string.Empty;
        }

        private ScriptInfo? FindScript(string name)
        {
            return _scripts.Find(s => s.Name.ToLower() == name.ToLower());
        }

        private void InitScripts()
        {
            
            //检查并确保ScriptsPath目录存在
            if (!Directory.Exists(this._scriptsDir))
            {
                Utils.WriteLine($"脚本目录【{this._scriptsDir}】不存在,是否创建该目录？(y/n)", ConsoleColor.Red);
                string input = Console.ReadLine() ?? "";
                if (input.ToLower() == "y")
                    Directory.CreateDirectory(this._scriptsDir);
                else
                    return;
            }
            if (!Directory.Exists(this._scriptsDir))
                return;
            //获取scriptsDir目录下的所有子目录
            string[] subDirs = Directory.GetDirectories(this._scriptsDir);
            foreach (string subDir in subDirs)
            {
                if (TryGetScript(subDir, out Script? nullableScript) && nullableScript is Script script)
                {
                    var mainFile = FindScriptFile(script, subDir);
                    if (mainFile != null)
                    {
                        var info = new ScriptInfo(script);
                        info.File = mainFile;
                        _scripts.Add(info);
                    }
                }
            }
        }

        private void CopyScriptDirectories(Dictionary<string, string> scriptInfos)
        {
            //将一些列文件夹sourceDirectories及其内部的所有文件，递归的复制到this._scriptsDir目录下
            foreach (string name in scriptInfos.Keys.ToList())
            {
                string sourceDirectory = scriptInfos[name];
                string scriptDir = Path.Join(this._scriptsDir, name);
                Utils.CopyDirectory(sourceDirectory, scriptDir);
            }
        }

        public void ShowScriptsAndHelp()
        {
            Utils.WriteLine("Scripts:", ConsoleColor.Blue);
            for (int i = 0; i < _scripts.Count; i++)
            {
                Utils.Write($"{(i + 1).ToString("00")}.", ConsoleColor.Yellow, ConsoleColor.Blue);
                Utils.Write("\t"+_scripts[i].Name, ConsoleColor.Blue);
                Utils.Write("\t\t-\t"+_scripts[i].Description + "\n", ConsoleColor.DarkGray);
            }

            Utils.WriteLine("使用脚本名称以运行对应脚本", ConsoleColor.DarkGray);
            Utils.WriteLine("------以下指令可选------", ConsoleColor.Green);
            Utils.WriteLine("new <script-name> 新建脚本", ConsoleColor.Green);
            Utils.WriteLine("import <scripts-directory> 导入脚本", ConsoleColor.Green);
            Utils.WriteLine("open 打开所有脚本程序目录", ConsoleColor.Green);
        }

        public void FindAndRunScript(List<string> argsList)
        {
            string key = argsList[0];
            ScriptInfo? scriptToRun = FindScript(key);
            if (scriptToRun == null)
            {
                Utils.WriteLine($"未找到名为【{key}】的脚本", ConsoleColor.Red);
                ShowScriptsAndHelp();
                return;
            }

            string argStr = "";
            string executor = "";
            if (!string.IsNullOrEmpty(scriptToRun.Executor))
            {
                executor = scriptToRun.Executor;
                argStr = argStr + "\"" + scriptToRun.File + "\"" + " ";
            }
            else
            {
                executor = scriptToRun.File;
            }
            if (argsList.Count > 1)
            {
                for (int i = 1; i < argsList.Count; i++)
                {
                    argStr = argStr + argsList[i] + " ";
                }
            }

            try
            {
                Utils.WriteLine($"😏▶️{executor} {argStr}⬇️", ConsoleColor.Blue);
                Utils.ExecuteScriptProcess(executor, argStr);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生异常: {ex.Message}");
            }
        }

        public bool OpenScriptsDirectory(List<string> argsList)
        {
            string key = argsList[0];
            if (key != "open")
                return false;
            if (argsList.Count > 1)
            {
                Utils.WriteLine("参数过多(请使用格式：open)，请重试", ConsoleColor.Red);
                return true;
            }
            
            try
            {                
                Utils.ExecuteScriptProcess("explorer.exe", this._scriptsDir);
            }
            catch (Exception ex)
            {
                Utils.WriteLine($"打开目录失败：{this._scriptsDir}", ConsoleColor.Red);
                return true;
            }
            return true;
        }

        public bool CreateNewScript(List<string> argsList)
        {
            string key = argsList[0];
            if (key != "new")
                return false;
            if (argsList.Count < 2)
            {
                Utils.WriteLine("缺少脚本名称(请使用格式：new <sript-name>)，请重试", ConsoleColor.Red);
                return true;
            }
            if (argsList.Count > 2)
            {
                Utils.WriteLine("参数过多(请使用格式：new <sript-name>)，请重试", ConsoleColor.Red);
                return true;
            }
            string name = argsList[1];
            if (_innerArgs.Contains(name.ToLower()))
            {
                Utils.WriteLine($"无效的脚本程序名称：{name}", ConsoleColor.Red);
                return true;
            }
            ScriptInfo? scriptToRun = FindScript(name);
            if (scriptToRun != null)
            {
                Utils.WriteLine("脚本已存在", ConsoleColor.Red);
                return true;
            }
            string path = AppDomain.CurrentDomain.BaseDirectory;            
            string dir = Path.Join(this._scriptsDir, name);
            try
            {
                Directory.CreateDirectory(dir);
                string infoFilePath = Path.Join(dir, "info.json");
                string infoStr = JsonConvert.SerializeObject(new Script { Name = name, Description = name, Extension = "exe" });
                File.WriteAllText(infoFilePath, infoStr);
                Utils.WriteLine("脚本创建成功", ConsoleColor.Blue);
                Utils.ExecuteScriptProcess("explorer.exe", dir);
            }
            catch (Exception ex)
            {
                Utils.WriteLine($"打开目录失败，请手动打开并编辑：{dir}", ConsoleColor.Red);
                return true;
            }
            return true;
        }

        public bool ImportScripts(List<string> argsList)
        {
            string key = argsList[0];
            if (key != "import")
                return false;
            if (argsList.Count < 2)
            {
                Utils.WriteLine("缺少脚本名称(请使用格式：import <sripts-directory>)，请重试", ConsoleColor.Red);
                return true;
            }
            if (argsList.Count > 2)
            {
                Utils.WriteLine("参数过多(请使用格式：import <sripts-directory)，请重试", ConsoleColor.Red);
                return true;
            }
            string directory = argsList[1];
            if (!Directory.Exists(directory))
            {
                Utils.WriteLine($"指定的目录不存在：{directory}", ConsoleColor.Red);
                return true;
            }
            List<string> scriptsCannotImport = new List<string>();
            Dictionary<string, string> scriptInfos = new Dictionary<string, string>();
            if (TryGetScript(directory, out Script? nullableScript1) && nullableScript1 is Script script1)
            {
                if (FindScript(script1.Name) != null || _innerArgs.Contains(script1.Name.ToLower()))
                {
                    scriptsCannotImport.Add(script1.Name);
                }
                else
                {
                    scriptInfos.Add(script1.Name, directory);
                }
            }
            else
            {
                string[] subDirs = Directory.GetDirectories(directory);
                foreach (string subDir in subDirs)
                {
                    if (TryGetScript(subDir, out Script? nullableScript2) && nullableScript2 is Script script2)
                    {
                        if (FindScript(script2.Name) != null || _innerArgs.Contains(script2.Name.ToLower()))
                        {
                            scriptsCannotImport.Add(script2.Name);
                        }
                        else
                        {
                            scriptInfos.Add(script2.Name, subDir);
                        }
                    }
                }
            }
            if (scriptsCannotImport.Count > 0)
            {
                Utils.WriteLine($"以下脚本已存在或为系统脚本：{string.Join(",", scriptsCannotImport)}", ConsoleColor.Red);
            }
            if (scriptInfos.Count == 0)
            {
                Utils.WriteLine("没有可导入的脚本", ConsoleColor.Red);
            }
            else
            {
                Utils.WriteLine("以下脚本将被导入：", ConsoleColor.Blue);
                foreach (string name in scriptInfos.Keys.ToList())
                {
                    Utils.WriteLine($"{name} : {scriptInfos[name]}");
                }
                Utils.WriteLine("是否导入？(y/n)", ConsoleColor.Green);
                string input = Console.ReadLine() ?? "";
                if (input.ToLower() == "y")
                {
                    CopyScriptDirectories(scriptInfos);
                }
                Utils.WriteLine($"成功添加(共计{scriptInfos.Count}个)", ConsoleColor.Blue);
            }
            return true;
        }

        private class ScriptInfo : Script
        {
            public ScriptInfo(Script script)
            {//填充基类的属性
                Name = script.Name;
                Description = script.Description;
                Executor = script.Executor;
                Extension = script.Extension;
            }
            public string File { get; set; }
        }
    }
}
